// Author : Kyoungho An
// $Id$
// This is the client program for the upstream sensors.  The sensor object
// inherits from ACE_Event_Handler so that we can register it to receive a
// timeout per expiry of the period.  The sensor then sends some data to the
// NEANode component.
//
// Sending of data is done periodically and handled at the NEANode.
// component using SERVER_DECLARED priority model.

#define DELAY 0
#define PACK_NUM 10
#include "ace/OS_NS_unistd.h"  // for OS API
#include "ace/Get_Opt.h"  // for parsing command line
#include "ace/Log_Msg.h"  // for logging messages
#include "ace/Reactor.h"  // Reactor class

#include "tao/ORB_Core.h" // the ORB itself
#include "tao/RTCORBA/RTCORBA.h"  // all the RTCORBA capabilities

#include "UpSensor.h" // our header

typedef struct Package_{
  int entityType;
  int delay;
}Package;

Package pack[PACK_NUM];
int totalEntityNum=0;
int count=0;

void mySleep(clock_t sec) // clock_t is a like typedef unsigned int clock_t. Use clock_t instead of integer in this context
{
  clock_t start_time = clock();
  clock_t end_time = sec * 1000000 + start_time;
  while(clock() != end_time);
}

// constructor
UpSensor::UpSensor (CORBA::ORB_ptr orb)
  : ACE_Event_Handler (orb->orb_core()->reactor ()),
    // since we hold a reference to the ORB, ensure we update the ref count by
    // using the _duplicate call 
    orb_ (CORBA::ORB::_duplicate (orb)),
    ior_ (CORBA::string_dup (ACE_TEXT("file://../usensor"))),
    freq_ (1),  // default rate
    timer_id_ (0),  // our timer identifier
    node_ (0) // no NEANode component as of now
{
      mySleep(DELAY);
      int i, j=0;

      char *inname = "PackageList";
      ifstream infile(inname);

      if (!infile) {
          std::cout << "Cannt open"
               << std::endl;
      }
      std::cout << "Opened " << inname << " for reading." << std::endl;
      while (infile >> i) {
      	pack[j].entityType = i;
        std::cout << "Entity Type is " << pack[j].entityType << std::endl;
	j++;
      }
      totalEntityNum = j;
      std::cout << "Total Entity Number is " << totalEntityNum << std::endl;
}

/// destructor
UpSensor::~UpSensor (void)
{
}

// parse the command line arguments other than those that will be consumed by
// the ORB
int UpSensor::parse_args (int argc, ACE_TCHAR *argv[])
{
  ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("F:k:"));
  int c;

  while ((c = get_opts ()) != -1)
    switch (c)
      {
      case 'k':  // if IOR of diagnostics module should be obtained via command
                 // line
        this->ior_ = get_opts.opt_arg ();
        break;

      case 'F':  // tire pressure sensing period
        this->freq_ = ACE_OS::atoi (get_opts.opt_arg ());
        break;

      case '?':
      default:
        ACE_ERROR_RETURN ((LM_ERROR,
                           "usage:  %s "
                           "-F <tire sensing frequency> "
                           "-k <ior for diagnostic module> "
                           "\n",
                           argv [0]),
                          -1);
      }

  // Indicates sucessful parsing of the command line
  return 0;
}



/// initialize
int UpSensor::init (void)
{

  try 
    {


      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("Grabbing obj ref to NEANode from file: %s\n"),
                  this->ior_.in ()));

      // let us grab the object reference to the NEANode module
      CORBA::Object_var object =
        this->orb_->string_to_object (this->ior_.in ());

      // check error
      if (CORBA::is_nil (object.in ())) {
        // failure to convert into obj ref
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("Block::Segment::UpSensor - bad object ref\n")));
        return -1;
      }

      // now narrow the obj ref to the NEANode type
      this->node_ = Block::Segment::SegmentNEANode::_narrow (object.in ());

      // check error
      if (CORBA::is_nil (this->node_.in ())) {
        // failure to narrow
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("Block::Segment::UpSensor - cannot narrow to NEANode\n")));
        return -1;
      }

      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("Scheduling timer: %d Hz\n"),
                  this->freq_));

      // now let us register ourselves for the timer corresponding to our
      // period. First create the timeout value.
      ACE_Time_Value tm;
      tm.set (1.0/this->freq_);  // use the overloaded function that
                                 // takes in a double.

      // now register
      this->timer_id_ = 
        this->reactor ()->schedule_timer (this,  // needs an event handler
                                          0,     // no argument to be passed
                                          tm,
                                          tm);   // time delay
      
      if (this->timer_id_ == -1) {
        // failure to register timer
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("Block::Segment::UpSensor - cannot schedule timer\n")));
        return -1;
      }
    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Exception caught:");
      return -1;
    }

  return 0;


}

/// invoked on a timeout
int UpSensor::handle_timeout (const ACE_Time_Value &current_time, const void *act)
{

  // now we reset our timer for the next period to start. As the period starts,
  // also do whatever work needs to be done.
#if 0
  ACE_Time_Value tm;
  tm.set (1.0/this->freq_);  // use the overloaded function that
                             // takes in a double.

  // now register
  if (this->reactor ()->reset_timer_interval (this->timer_id_,  // needs ID
                                              tm) == -1) {   // time delay
    // failure to register timer
    ACE_ERROR ((LM_ERROR,
                ACE_TEXT ("Block::Segment::UpSensor - cannot reschedule timer (%m)\n")));
    return -1;
  }
#endif
  // now send it
  try 
    {
      if(count==PACK_NUM)
        count=0;
      switch(pack[count].entityType){
        case 0: 
          this->node_->send_value_to_controller (Block::Segment::UP_SENSOR, Block::SMALL_PACKAGE);
          ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Small package is sensed\n")));
	  break;
        case 1: 
          this->node_->send_value_to_controller (Block::Segment::UP_SENSOR, Block::MEDIUM_PACKAGE);
          ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Medium package is sensed\n")));
	  break;
        case 2: 
          this->node_->send_value_to_controller (Block::Segment::UP_SENSOR, Block::LARGE_PACKAGE);
          ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Large package is sensed\n")));
	  break;
        default:
	  break;
      }
      count++;
    } 
  catch (const CORBA::Exception& ex) 
    {
      ex._tao_print_exception ("Exception caught in sending sensor value: ");
      return -1;
    }

  // success
  return 0;
}

